package com.ww.microrpc.rpc;

import com.ww.microrpc.client.Client;
import org.springframework.util.Assert;

import java.lang.reflect.Method;
import java.lang.reflect.Type;

public abstract class MicroRpc {

    public MicroRpc() {
    }

    /**
     * Configuration keys are formatted as unresolved
     *
     * @param targetType {@link Target#type() type} of the MicroRpc interface.
     * @param method invoked method, present on {@code type} or its super.
     * @see MethodMetadata#configKey()
     */
    public static String configKey(Class targetType, Method method) {
        StringBuilder builder = new StringBuilder();
        builder.append(targetType.getSimpleName());
        builder.append('#').append(method.getName()).append('(');
        for (Type param : method.getGenericParameterTypes()) {
            param = Types.resolve(targetType, targetType, param);
            builder.append(Types.getRawType(param).getSimpleName()).append(',');
        }
        if (method.getParameterTypes().length > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }
        return builder.append(')').toString();
    }

    /**
     * @deprecated use {@link #configKey(Class, Method)} instead.
     */
    @Deprecated
    public static String configKey(Method method) {
        return configKey(method.getDeclaringClass(), method);
    }

    public abstract <T> T newInstance(Target<T> target);

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        // 定义参数解析器
        private Contract contract = new Contract.Default();
        private Client client = null;
        private InvocationHandlerFactory invocationHandlerFactory =
                new InvocationHandlerFactory.Default();

        public <T> T target(Target<T> target) {
            return build().newInstance(target);
        }

        public Builder client(Client client) {
            this.client = client;
            return this;
        }
        public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
            this.invocationHandlerFactory = invocationHandlerFactory;
            return this;
        }
        public Builder contract(Contract contract) {
            this.contract = contract;
            return this;
        }

        public MicroRpc build() {
            Assert.notNull(client, "must set client object that implements com.ww.microrpc.client.Client ");

            SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
                    new SynchronousMethodHandler.Factory(client);

            ReflectiveMicroRpc.ParseHandlersByName handlersByName =
                    new ReflectiveMicroRpc.ParseHandlersByName(contract, synchronousMethodHandlerFactory);

            return new ReflectiveMicroRpc(handlersByName, invocationHandlerFactory);
        }
    }
}
